<!DOCTYPE html>
<html>
    <head>
        <title>Example 01</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <style>
            html, body {
                margin: 0px;
                padding: 0px;
                overflow: hidden;
                width: 100%;
                height: 100%;
                font-family: sans-serif;
            }
            canvas {
                width: 100%;
                height: 100%;
                top: 0;
                left: 0;
                position: absolute;
            }
            #dialog {
                display: none;
                width: 100%;
                height: 100%;
                top: 0;
                left: 0;
                position: absolute;
                text-align: center;
                padding-top: 10%;
            }  
            #message {
                font-size: 500%;
                color: navy;
            }
            .button {
                display: inline-block;
                width: 200px;
                color: white;
                border: 1px solid mediumblue;
                background-color: royalblue; 
                cursor: pointer;
            }

        </style>
        <script src="../src/Utils.js"></script>
        <script src="../src/ObjectContainer.js"></script>
        <script src="../src/EventSet.js"></script>
        <script src="../src/GameLoop.js"></script>
        <script src="../src/KeyboardInput.js"></script>
        <script src="../src/Screen.js"></script>
        <script src="../src/MouseInput.js"></script>
        <script src="../src/StateMap.js"></script>
        <script src="../src/CommandQueue.js"></script>
        <script>

            function sign(n) {
                return n < 0 ? -1 : 1;
            }

            function range2(a, b) {
                return Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2);
            }

            function Ship(id, p, v, a) {
                this.id = id;
                this.p = p;
                this.v = v;
                this.a = a;
                this.t = 0.0002;
                this.w = 0.002;
                this.maxV = 0.04;
                this.strokeStyle = '#000000';
                
                this.commands = new CommandQueue(id);
                this.now;
                this.states = new StateMap(id);
                this.states.source(this.commands);

                this.states.on.out((function(command) {                    
                    if (command)
                        switch (command.which) {
                            case 'FIRE':
                                if (command.state) this.fire();
                                break;
                            case 'ACCELERATE':
                                if (command.state) {
                                    this.accelerating = command.time;
                                } else {
                                    this.accelerate(this.now - command.time);
                                    this.accelerating = 0;
                                }
                                break;
                            case 'TURN_LEFT':
                                if (command.state) {
                                    this.direction = -1;
                                    this.rotating = command.time;
                                } else {
                                    this.rotate(this.now - command.time);
                                    if (this.states.get('TURN_RIGHT')) {
                                        this.direction = 1;
                                        this.rotating = command.time;
                                    } else {
                                        this.rotating = 0;
                                    }
                                }
                                break;
                            case 'TURN_RIGHT':
                                if (command.state) {
                                    this.direction = 1;
                                    this.rotating = command.time;
                                } else {
                                    this.rotate(this.now - command.time);
                                    if (this.states.get('TURN_LEFT')) {
                                        this.direction = -1;
                                        this.rotating = command.time;
                                    } else {
                                        this.rotating = 0;
                                    }
                                }
                                break;
                        }
                }).bind(this));
            }
            ;

            Ship.prototype.run = function(delta) {
                this.p.sum(this.v, delta);
                if (this.p.x < 0)
                    this.p.x += canvas.width;
                if (this.p.x >= canvas.width)
                    this.p.x -= canvas.width;
                if (this.p.y < 0)
                    this.p.y += canvas.height;
                if (this.p.y >= canvas.height)
                    this.p.y -= canvas.height;
            };

            Ship.prototype.accelerate = function(delta) {
                if (this.accelerating) {
                    this.v.x = this.v.x + delta * this.t * Math.cos(this.a);
                    this.v.y = this.v.y + delta * this.t * Math.sin(this.a);
                    var len = this.v.len();
                    if (len > this.maxV) {
                        this.v.mul(1 / len * this.maxV);
                    }
                }
            };

            Ship.prototype.rotate = function(delta) {                
                if (this.rotating) {
                    this.a += Math.PI * this.w * delta * this.direction;
                }
            };

            Ship.prototype.update = function(delta, now) {
                this.now = now;
                while (this.commands.next());
                this.accelerate(delta);
                this.rotate(delta);
                this.run(delta);
            };

            Ship.prototype.render = function() {
                ctx.save();
                ctx.strokeStyle = this.strokeStyle;
                ctx.beginPath();                
                ctx.arc(this.p.x, this.p.y, 10, this.a, 2 * Math.PI + this.a - 0.001);
                ctx.lineTo(this.p.x, this.p.y);
                ctx.stroke();
                ctx.restore();
            };

            Ship.prototype.fire = function() {                
                var p = this.p.copy().sum(new Vector2d(Math.cos(this.a), Math.sin(this.a)).mul(9)),
                    v = this.v.copy().sum(new Vector2d(Math.cos(this.a), Math.sin(this.a)).mul(0.2));
                objects.add(new Torpedo(p, v));
            };


            function PlayerShip(id, p, v, a) {
                this.super.constructor.apply(this, arguments);
                this.strokeStyle = '#0000ff';
                this.commands.source(sm, {
                    INSERT: 'FIRE',
                    UP: 'ACCELERATE',
                    LEFT: 'TURN_LEFT',
                    RIGHT: 'TURN_RIGHT'
                });
            }

            Utils.extend(PlayerShip, Ship);
            
            
            function EnemyShip(id, p, v, a) {
                this.super.constructor.apply(this, arguments);
                this.strokeStyle = '#ff0000';
                this.commands.source(sm, {
                    BACK_QUOTE: 'FIRE',
                    W: 'ACCELERATE',
                    A: 'TURN_LEFT',
                    D: 'TURN_RIGHT'
                });
            }

            Utils.extend(EnemyShip, Ship);
            

            function Torpedo(p, v, timer) {
                this.p = p;
                this.v = v;                
                this.timer = timer ? parseInt(timer) : 1500;
            };

            Torpedo.prototype.update = function(delta, now) {
                
                this.p.sum(this.v, delta);
                if (this.p.x < 0)
                    this.p.x += canvas.width;
                if (this.p.x >= canvas.width)
                    this.p.x -= canvas.width;
                if (this.p.y < 0)
                    this.p.y += canvas.height;
                if (this.p.y >= canvas.height)
                    this.p.y -= canvas.height;

                this.timer -= delta;
                if (this.timer <= 0)
                    objects.remove(this);

                if (this.p.diff2(player.p) < 98)
                    couter_win();
                if (this.p.diff2(enemy.p) < 98)
                    terror_win();
            };

            Torpedo.prototype.render = function() {
                ctx.beginPath();
                ctx.arc(this.p.x, this.p.y, 2, 0, 2 * Math.PI);
                ctx.stroke();
            };

            function start() {
                document.querySelector('#dialog').style.display = 'none';                
                objects.empty();
                player = new PlayerShip(
                        'player',
                        new Vector2d(
                                Math.random() * 200 + 128,
                                Math.random() * (canvas.height - 40) + 20
                                ),
                        new Vector2d(0, 0),
                        Math.PI * Math.random()
                        );
                enemy = new EnemyShip(
                        'enemy',
                        new Vector2d(
                                canvas.width - 128 - Math.random() * 200,
                                Math.random() * (canvas.height - 40) + 20
                                ),
                        new Vector2d(0, 0),
                        Math.PI * Math.random()
                        );
                objects.add(player);
                objects.add(enemy);
                game.start();
                sm.enable();
                mm.disable();
            }

            function couter_win() {
                sm.disable();
                mm.enable();
                game.stop();
                document.querySelector('#message').innerHTML = 'Counter-terrorists win!';
                document.querySelector('#dialog').style.display = 'block';
            }

            function terror_win() {
                sm.disable();
                mm.enable();
                game.stop();
                document.querySelector('#message').innerHTML = 'Terrorists win!';
                document.querySelector('#dialog').style.display = 'block';
            }

            window.addEventListener('load', function() {
                canvas = document.querySelector('canvas'),
                        ctx = canvas.getContext('2d');
                screen = new Screen(canvas);
                
                kb = new KeyboardInput();
                //mb = new MouseInput(screen);
                
                sm = new StateMap('controls');
                sm.source(kb, KeyboardInput.keyMap);
                
                mm = new StateMap('splash');
                mm.disable();
                mm.source(kb, KeyboardInput.keyMap);                
                mm.on.out(function (command) {if (command.which === 'SPACE' && command.state) start(); });
        
                objects = new ObjectContainer();

                game = new GameLoop();
                game.on.add('update', function(delta, now) {
                    objects.each(function(object) {
                        object.update(delta, now);
                    });
                });
                game.on.add('render', function() {
                    ctx.clearRect(0, 0, canvas.width, canvas.height);
                    objects.each(function(object) {
                        object.render();
                    });
                });

                start();
            });
        </script>
    </head>
    <body>
        <canvas></canvas>
        <div id="dialog">
            <h1 id="message"></h1>
            <div class="button" onclick="start()">Press &lsaquo;Space&rsaquo; to start.</div>
        </div>
    </body>
</html>
